#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <string>
#include <process.h>

static HMODULE habpa = NULL;

typedef std::basic_string<TCHAR> tstring;

// This manual code replaces automatic load procedure,
// based on registry key
void load_abpa() {
	habpa = ::LoadLibrary(_T("abpa_loader.dll"));
	if (habpa == NULL) {
		LPVOID lpMsgBuf;
		::FormatMessage( 
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM | 
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			GetLastError(),
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
			(LPTSTR) &lpMsgBuf,
			0,
			NULL);
		_tprintf(_T("FAILED TO LOAD ABPA: %s\n"), (LPCTSTR)lpMsgBuf);
		::LocalFree(lpMsgBuf);
	}
}

unsigned int __stdcall WriteToGivenFile(void *param) {
	HANDLE hf = ::CreateFile(reinterpret_cast<LPTSTR>(param), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	DWORD dw;
	::WriteFile(hf, "in thread", 10, &dw, 0);
	::CloseHandle(hf);

	return 10;
}

int main() {
	load_abpa();

	TCHAR tmppath[MAX_PATH];
	::GetEnvironmentVariable(_T("TEMP"), tmppath, MAX_PATH);

	tstring fname(tmppath);
	fname += _T('\\');
	fname += _T("abpa_test.txt");
	HANDLE hf1 = ::CreateFile(fname.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	fname = tmppath;
	fname += _T('\\');
	fname += _T("abpa_test.html");
	HANDLE hf2 = ::CreateFile(fname.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	
	DWORD dw;
	for (int i = 0; i < 2; i++) {
		::WriteFile(hf1, "test", 4, &dw, 0);
		::WriteFile(hf2, "<html/>", 8, &dw, 0);
	}

	::Sleep(25);

	// test VirtualAlloc
	void *p = ::VirtualAlloc(NULL, 1024*10, MEM_COMMIT, PAGE_READWRITE);

	// test Threads
	unsigned int threadID;
	fname = tmppath;
	fname += _T('\\');
	fname += _T("abpa_test_thread.txt");
	HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, WriteToGivenFile, const_cast<void*>(static_cast<const void *>(fname.c_str())), 0, &threadID);
	::WaitForSingleObject(hThread, INFINITE);


	/*while(1)*/ ::Sleep(1000);

	return 0;
}